﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Resources;
using System.Xml.Linq;

namespace Moonwish.Silverlight.OsAvatar.Utility
{
    /// <summary>
    /// 下载Xap包程序集，write by zhlin 2011-08-12
    /// </summary>
    public class XapLoader
    {
        public event DynamicInstanceEventHandler DynamicInstanceCreated;

        public XapLoader(string xap, string targetType)
        {
            Xap = xap;

            TargetType = targetType;
        }

        public string Xap { get; set; }

        public string TargetType { get; set; }

        public void DownloadFromRemote()
        {
            try
            {
                if (Xap.Trim() != string.Empty)
                {
                    var client = new WebClient();
                    client.OpenReadCompleted += proxy_GetProgramCompleted;
                    client.OpenReadAsync(new Uri(Xap, UriKind.RelativeOrAbsolute));
                }
            }
            catch (Exception)
            {
            }
        }


        private void proxy_GetProgramCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            try
            {
                var memoryStream = e.Result;
                var xElement = XDocument.Parse(new StreamReader(Application.GetResourceStream(new StreamResourceInfo(memoryStream, null), new Uri("AppManifest.xaml", UriKind.RelativeOrAbsolute)).Stream).ReadToEnd()).Root;
                if (xElement != null)
                {
                    List<XElement> list = (from assemblyParts in xElement.Elements().Elements() select assemblyParts).ToList<XElement>();
                    Assembly assembly = null;
                    int num = 0;
                    foreach (XElement element2 in list)
                    {
                        var xAttribute = element2.Attribute("Source");
                        if (xAttribute != null)
                        {
                            string uriString = xAttribute.Value;
                            if (!uriString.EndsWith(".zip"))
                            {
                                var part = new AssemblyPart();
                                var resourceStream =
                                    Application.GetResourceStream(new StreamResourceInfo(memoryStream, "application/binary"),
                                                                  new Uri(uriString, UriKind.RelativeOrAbsolute));
                                try
                                {
                                    if (num == 0)
                                    {
                                        assembly = part.Load(resourceStream.Stream);
                                    }
                                    else
                                    {
                                        part.Load(resourceStream.Stream);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    if (DynamicInstanceCreated != null)
                                    {
                                        DynamicInstanceCreated(this, new DynamicInstanceEventArgs(ex));
                                    }
                                }
                                num++;
                            }
                            else
                            {
                                var client = new WebClient();
                                client.OpenReadCompleted += (s, arg) =>
                                {
                                    try
                                    {
                                        var ms =
                                            Application.GetResourceStream(
                                                new StreamResourceInfo(arg.Result, "application/binary"),
                                                new Uri(uriString.Replace(".zip", ".dll"), UriKind.RelativeOrAbsolute));
                                        var p = new AssemblyPart();
                                        p.Load(ms.Stream);

                                        if (assembly != null)
                                        {
                                            var type = (from t in assembly.GetTypes()
                                                        where t.FullName != null && (t.FullName.IndexOf(TargetType, StringComparison.Ordinal) != -1 && t.IsClass)
                                                        select t).FirstOrDefault<Type>();
                                            if (type == null)
                                            {
                                                if (DynamicInstanceCreated != null)
                                                {
                                                    DynamicInstanceCreated(this, new DynamicInstanceEventArgs(new Exception("要创建的类型不存在。")));
                                                }
                                                return;
                                            }
                                            num++;
                                            if (num == list.Count)
                                            {
                                                if (type.FullName != null)
                                                {
                                                    var content = assembly.CreateInstance(type.FullName) as FrameworkElement;
                                                    if (DynamicInstanceCreated != null)
                                                    {
                                                        DynamicInstanceCreated(this, new DynamicInstanceEventArgs(content));
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    catch(Exception ex)
                                    {
                                        if (DynamicInstanceCreated != null)
                                        {
                                            DynamicInstanceCreated(this, new DynamicInstanceEventArgs(ex));
                                        }
                                    }
                                };
                                client.OpenReadAsync(new Uri(uriString, UriKind.RelativeOrAbsolute));
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {

            }
        }
    }

    public delegate void DynamicInstanceEventHandler(object sender, DynamicInstanceEventArgs element);

    public class DynamicInstanceEventArgs : EventArgs
    {
        public DynamicInstanceEventArgs(FrameworkElement element)
        {
            Element = element;
        }
        public DynamicInstanceEventArgs(Exception error)
        {
            Error = error;
        }

        public FrameworkElement Element { get; set; }

        public Exception Error { get; set; }
    }
}
